/*
	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Library General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
*/

#include <QtGui>

#include "mainwindowimpl.h"
#include "searchboximpl.h"
#include "styleeditorimpl.h"
#include "configurationdlgimpl.h"
#include "aboutdialogimpl.h"
#include "propertydlgimpl.h"
#include "inserttabledlgimpl.h"
#include "templatesmanagerdlgimpl.h"
#include "insertimagedlgimpl.h"
#include "constantes.h"

/*
	MainWindow construtor.
*/
MainWindowImpl::MainWindowImpl( QWidget * parent, Qt::WFlags f)
        : QMainWindow(parent, f)
{
    // Setup UI
    setupUi(this);

    // Load configuration
    m_confManager = new ConfigurationManager(Constantes::APP_NAME);

	if (!m_confManager->isFileVersionCorrect())
	{
		QMessageBox::warning(this, tr("Warning"), tr("Your configuration file does not met current Nagaina version. The following settings have been reseted to their default value:\n\n") + 
							m_confManager->getResetedSettingsList() + "\n\n" + 
							tr("This message will not be displayed next time you launch Nagaina."));
	}

    // Load templates
    m_templatesManager = new TemplateManager();

	// Load styles
	m_styleManager = new StyleManager();
	m_stylesGroup = NULL;

	initTemplateActionList();

    createTreeDock();
    createSearchDock();
    createToolBars();
    createContextMenu();
    createSysTray();
    FinalizeUI();
    
    updateTemplateActionList();
    updateStylesActionList();

    searchBox->setTree(treeWidget);

    mainModel = NULL;
    m_closeFromMenu = false;

    // Create help dialog
    helpDlg = new HelpDlgImpl(this, 0);

    // Apply configuration
    applyConfiguration();

    // Read window, toolbars and docks size/position.
    readSettings();

    // Open last file if requested, else open an empty new file.
    if (m_confManager->openLastFile)
        openFile(m_confManager->lastFile);
    else
    {
        on_action_New_triggered();
    }
}

/*
	UI complementary implementation.
*/

/*
	Misc. UI stuff.
*/
void MainWindowImpl::FinalizeUI()
{
    // Main window title
    this->setWindowTitle(Constantes::APP_DISPLAY_NAME + " - " + Constantes::APP_VERSION);

    // Add toolbar to menu
    menu_Toolbars->addAction(fileToolBar->toggleViewAction());
    menu_Toolbars->addAction(editToolBar->toggleViewAction());
    menu_Toolbars->addAction(formatToolBar->toggleViewAction());
    menu_Toolbars->addAction(styleToolBar->toggleViewAction());
    menu_Toolbars->addAction(fontToolBar->toggleViewAction());
    menu_Toolbars->addAction(insertToolBar->toggleViewAction());

    // Initialize "paste" action.
    connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(onClipboardDataChanged()));
    actionPaste->setEnabled(!QApplication::clipboard()->text().isEmpty());

    onFontChanged(textEdit->font());
    onColorChanged(textEdit->textColor());
    onAlignmentChanged(textEdit->alignment());
}

/*
	Create tool bars.
*/
void MainWindowImpl::createToolBars()
{
    // Style tool bar
    styleToolBar = new QToolBar(this);
    styleToolBar->setObjectName("styleToolBar");
    styleToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea | Qt::LeftToolBarArea | Qt::RightToolBarArea);
    styleToolBar->setWindowTitle(tr("Styles"));
    addToolBarBreak(Qt::TopToolBarArea);
    addToolBar(styleToolBar);

    comboStyle = new QComboBox(styleToolBar);
    comboStyle->setObjectName("comboStyle");
    comboStyle->setEditable(false);
    comboStyle->setSizeAdjustPolicy(QComboBox::AdjustToContents);
	connect(comboStyle, SIGNAL(currentIndexChanged ( const QString & )), this, SLOT(onComboSelectStyle(QString )));
    
    styleToolBar->addWidget(comboStyle);
    connect(action_Apply_current_style, SIGNAL(triggered()), this, SLOT(on_action_Apply_current_style_triggered()));
    styleToolBar->addAction(action_Apply_current_style);

    // Create Toolbar for size and police combos.
    fontToolBar = new QToolBar(this);
    fontToolBar->setObjectName("fontToolBar");
    fontToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea | Qt::LeftToolBarArea | Qt::RightToolBarArea);
    fontToolBar->setWindowTitle(tr("Font"));
    addToolBar(fontToolBar);

    // Police combo.
    comboFont = new QFontComboBox(fontToolBar);
    fontToolBar->addWidget(comboFont);
    connect(comboFont, SIGNAL(activated(const QString &)),
            this, SLOT(onTextFamily(const QString &)));
    comboFont->setEditable(false);

    // Size combo.
    comboSize = new QComboBox(fontToolBar);
    comboSize->setObjectName("comboSize");
    fontToolBar->addWidget(comboSize);
    comboSize->setEditable(false); 

    // Fill size combo.
    QFontDatabase db;
    foreach(int size, db.standardSizes())
    comboSize->addItem(QString::number(size));
    connect(comboSize, SIGNAL(activated(const QString &)), this, SLOT(onTextSize(const QString &)));
    comboSize->setCurrentIndex(comboSize->findText(QString::number(QApplication::font().pointSize())));

    // Color action : draw with current color.
    QPixmap pix(16, 16);
    pix.fill(Qt::black);
    action_Color->setIcon(pix);

    // Alignment actions.
    QActionGroup *grp = new QActionGroup(this);
    connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(onTextAlign(QAction *)));

    actionAlignLeft = new QAction(QIcon(":/textleft.png"), tr("&Left"), grp);
    actionAlignLeft->setShortcut(Qt::CTRL + Qt::Key_L);
    actionAlignLeft->setCheckable(true);
    actionAlignCenter = new QAction(QIcon(":/textcenter.png"), tr("C&enter"), grp);
    actionAlignCenter->setShortcut(Qt::CTRL + Qt::Key_E);
    actionAlignCenter->setCheckable(true);
    actionAlignRight = new QAction(QIcon(":/textright.png"), tr("&Right"), grp);
    actionAlignRight->setShortcut(Qt::CTRL + Qt::Key_R);
    actionAlignRight->setCheckable(true);
    actionAlignJustify = new QAction(QIcon(":/textjustify.png"), tr("&Justify"), grp);
    actionAlignJustify->setShortcut(Qt::CTRL + Qt::Key_J);
    actionAlignJustify->setCheckable(true);

    formatToolBar->addActions(grp->actions());
    menuAlignment->addActions(grp->actions());

    // Insertion toolbar
    insertToolBar = new QToolBar(this);
    insertToolBar->setObjectName("insertToolBar");
    insertToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea | Qt::LeftToolBarArea | Qt::RightToolBarArea);
    insertToolBar->setWindowTitle(tr("Insert"));
    addToolBar(insertToolBar);

    insertToolBar->addAction(actionInsert_current_date);
    insertToolBar->addAction(actionInsert_current_time);
    insertToolBar->addAction(actionInsert_image);
    insertToolBar->addAction(actionInsert_table);
}

/*
	Create Systray object
*/
void MainWindowImpl::createSysTray()
{
    m_trayIcon = new QSystemTrayIcon(QIcon(":/nagaina.png"), this);
    m_trayIcon->setToolTip(Constantes::APP_DISPLAY_NAME);
    connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason )), this, SLOT(onTrayIconActivated(QSystemTrayIcon::ActivationReason )));
}

/*
	Create Tree Widget context menu.
*/
void MainWindowImpl::createContextMenu()
{
    actionAddRootCategory = new QAction(QIcon(":/addrootcategory.png"), tr("Add root category..."), this);
    connect(actionAddRootCategory, SIGNAL(triggered( )), this, SLOT(onActionAddRootCategory( )));
    actionAddRootPage = new QAction(QIcon(":/addrootpage.png"), tr("Add root page..."), this);
    connect(actionAddRootPage, SIGNAL(triggered( )), this, SLOT(onActionAddRootPage( )));

    actionMenuAddCategory = new QAction(QIcon(":/addcategory.png"), tr("Add category..."), this);
    connect(actionMenuAddCategory, SIGNAL(triggered( )), this, SLOT(onActionMenuAddCategory( )));
    actionMenuAddPage = new QAction(QIcon(":/addpage.png"), tr("Add page..."), this);
    connect(actionMenuAddPage, SIGNAL(triggered( )), this, SLOT(onActionMenuAddPage( )));
    actionMenuRename = new QAction(tr("Rename..."), this);
    connect(actionMenuRename, SIGNAL(triggered( )), this, SLOT(onActionMenuRename( )));
    actionMenuDelete = new QAction(QIcon(":/delete.png"), tr("Delete..."), this);
    connect(actionMenuDelete, SIGNAL(triggered( )), this, SLOT(onActionMenuDelete( )));

    actionMenuMoveLeft = new QAction(QIcon(":/leftarrow.png"), tr("Move left"), this);
    actionMenuMoveLeft->setShortcut(Qt::ALT + Qt::Key_Left);
    connect(actionMenuMoveLeft, SIGNAL(triggered( )), this, SLOT(onActionMenuMoveLeft( )));
    actionMenuMoveRight = new QAction(QIcon(":/rightarrow.png"), tr("Move right"), this);
    actionMenuMoveRight->setShortcut(Qt::ALT + Qt::Key_Right);
    connect(actionMenuMoveRight, SIGNAL(triggered( )), this, SLOT(onActionMenuMoveRight( )));
    actionMenuMoveUp = new QAction(QIcon(":/uparrow.png"), tr("Move up"), this);
    actionMenuMoveUp->setShortcut(Qt::ALT + Qt::Key_Up);
    connect(actionMenuMoveUp, SIGNAL(triggered( )), this, SLOT(onActionMenuMoveUp( )));
    actionMenuMoveDown = new QAction(QIcon(":/downarrow.png"), tr("Move down"), this);
    actionMenuMoveDown->setShortcut(Qt::ALT + Qt::Key_Down);
    connect(actionMenuMoveDown, SIGNAL(triggered( )), this, SLOT(onActionMenuMoveDown( )));

    actionMenuProperty = new QAction(tr("Property..."), this);
    connect(actionMenuProperty, SIGNAL(triggered( )), this, SLOT(onActionMenuProperty( )));

    actionMenuAddCategory->setEnabled(false);
    actionMenuAddPage->setEnabled(false);
    actionMenuRename->setEnabled(false);
    actionMenuDelete->setEnabled(false);
    actionMenuMoveUp->setEnabled(false);
    actionMenuMoveDown->setEnabled(false);
    actionMenuMoveLeft->setEnabled(false);
    actionMenuMoveRight->setEnabled(false);
    actionMenuProperty->setEnabled(false);

    // Add actions to context menu.
    contextMenu = new QMenu(this);
    contextMenu->addAction(actionMenuAddCategory);
    contextMenu->addAction(actionMenuAddPage);
    contextMenu->addSeparator();
    contextMenu->addAction(actionMenuMoveUp);
    contextMenu->addAction(actionMenuMoveDown);
    contextMenu->addAction(actionMenuMoveLeft);
    contextMenu->addAction(actionMenuMoveRight);
    contextMenu->addSeparator();
    contextMenu->addAction(actionMenuRename);
    contextMenu->addAction(actionMenuDelete);
    contextMenu->addSeparator();
    contextMenu->addAction(actionMenuProperty);

    // Add actions to tree view tool bar
    treeToolBar->addAction(actionAddRootCategory);
    treeToolBar->addAction(actionAddRootPage);
    treeToolBar->addAction(actionMenuMoveUp);
    treeToolBar->addAction(actionMenuMoveDown);
    treeToolBar->addAction(actionMenuMoveLeft);
    treeToolBar->addAction(actionMenuMoveRight);

    // Add actions to main menu.
    menuItems->addAction(actionAddRootCategory);
    menuItems->addAction(actionAddRootPage);
    menuItems->addSeparator();
    menuItems->addAction(actionMenuAddCategory);
    menuItems->addAction(actionMenuAddPage);
    menuItems->addSeparator();
    menuItems->addAction(actionMenuMoveUp);
    menuItems->addAction(actionMenuMoveDown);
    menuItems->addAction(actionMenuMoveLeft);
    menuItems->addAction(actionMenuMoveRight);
    menuItems->addSeparator();
    menuItems->addAction(actionMenuRename);
    menuItems->addAction(actionMenuDelete);
    menuItems->addSeparator();
    menuItems->addAction(actionMenuProperty);
}

/*
	Create file TreeView in a dock.
*/
void MainWindowImpl::createTreeDock()
{
    QDockWidget *dock = new QDockWidget(tr("Explorer"), this);
    dock->setObjectName("dockExplorer");
    dock->setAllowedAreas(Qt::AllDockWidgetAreas);

    QWidget *container = new QWidget;
    container->setContentsMargins(0, 0, 0, 0);
    QVBoxLayout *layout = new QVBoxLayout();
    layout->setMargin(0);
    layout->setSpacing(0);

    treeWidget = new QTreeWidget(dock);
    treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
    treeWidget->setHeaderLabel("");

    connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(onTreeClick(QTreeWidgetItem *, int)));
    connect(treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onTreeContextMenuRequested(QPoint)));
    connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(onCurrentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));

    treeToolBar = new QToolBar(dock);
    treeToolBar->setIconSize(QSize(20, 20));
    treeToolBar->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum));

    layout->addWidget(treeToolBar);
    layout->addWidget(treeWidget);

    container->setLayout(layout);

    dock->setWidget(container);
    addDockWidget(Qt::LeftDockWidgetArea, dock);
    dock->toggleViewAction()->setShortcut(Qt::Key_F6);
    menu_Display->addAction(dock->toggleViewAction());
}

/*
	Create advanced search dialog dock.
*/
void MainWindowImpl::createSearchDock()
{
    searchBox = new SearchBoxImpl(0);
    searchDock = searchBox->dockWidget;

    addDockWidget(Qt::LeftDockWidgetArea, searchDock);

    searchDock->toggleViewAction()->setShortcut(Qt::CTRL + Qt::Key_F);
    menu_Display->addAction(searchDock->toggleViewAction());

    searchBox->cbWholeWord->setChecked(m_confManager->searchWholeWord);
    searchBox->cbCaseSensitive->setChecked(m_confManager->searchCaseSensitive);
    searchBox->cbScopePage->setChecked(m_confManager->searchInPages);
    searchBox->cbScopeCategory->setChecked(m_confManager->searchInCategories);
    searchBox->cbScopeTags->setChecked(m_confManager->searchInTags);

    connect(searchBox, SIGNAL(onSearchSelectionTriggered(QTreeWidgetItem * , int , int )), this, SLOT(onSearchSelection(QTreeWidgetItem * , int , int )));
    
    searchDock->setVisible(false);
}

void MainWindowImpl::setEditorColor(QColor color)
{
    QVariant red = color.red();
    QVariant green = color.green();
    QVariant blue = color.blue();

    textEdit->setStyleSheet("QTextEdit { background-color: rgb(" + red.toString() + ", " + green.toString() + ", " + blue.toString() + "); color: black; }");
}

void MainWindowImpl::setTreeColor(QColor color)
{
    QVariant red = color.red();
    QVariant green = color.green();
    QVariant blue = color.blue();
    treeWidget->setStyleSheet("QTreeWidget { background-color: rgb(" + red.toString() + ", " + green.toString() + ", " + blue.toString() + "); color: black; }");
}

void MainWindowImpl::updateStylesActionList()
{
	if (m_stylesGroup != NULL)
	{
		delete m_stylesGroup;
		m_stylesGroup = NULL;
	}
	
	QString currentText;
	if (comboStyle->count() > 0)
		currentText = comboStyle->currentText();
	else
		currentText = "";
	
	disconnect(comboStyle, SIGNAL(currentIndexChanged ( const QString & )), this, SLOT(onComboSelectStyle(QString )));
	comboStyle->clear();
	connect(comboStyle, SIGNAL(currentIndexChanged ( const QString & )), this, SLOT(onComboSelectStyle(QString )));

	
	m_stylesGroup = new QActionGroup(this);
	connect(m_stylesGroup, SIGNAL(triggered(QAction *)), this, SLOT(onSelectStyle(QAction *)));	
	
	for (int i = 0; i < m_styleManager->getStyleCount(); i++)
	{
		if (m_styleManager->isStyleSelected(i))
		{
			QAction *newAction = new QAction(m_styleManager->getStyleName(i), m_stylesGroup);
			newAction->setCheckable(true);
			comboStyle->addItem(m_styleManager->getStyleName(i), i);
		}
	}
	menuStyles->addActions(m_stylesGroup->actions());
	
	if (currentText != "")
	{
		int index = comboStyle->findText(currentText);
		if (index != -1)
			comboStyle->setCurrentIndex(index);
		else
			comboStyle->setCurrentIndex(0);
	}
	else
		comboStyle->setCurrentIndex(0);
}

void MainWindowImpl::initTemplateActionList()
{
	for (int i = 0; i < Constantes::NB_MAX_TEMPLATES; i++)
		m_templatesArray[i] = NULL;
}

void MainWindowImpl::updateTemplateActionList()
{
	for (int i = 0; i < Constantes::NB_MAX_TEMPLATES; i++)
	{
		if (m_templatesArray[i] != NULL)
		{
			menuTemplates->removeAction(m_templatesArray[i]);
			delete m_templatesArray[i];
			m_templatesArray[i] = NULL;
		}
	}
	
	for (int i = 0; i < m_templatesManager->getTemplateCount(); i++)
	{
		if (m_templatesManager->isTemplateSelected(i))
		{
			m_templatesArray[i] = new QAction(m_templatesManager->getTemplateName(i), 0);
			connect(m_templatesArray[i], SIGNAL(triggered( )), this, SLOT(onInsertTemplate( )));
			menuTemplates->addAction(m_templatesArray[i]);
		}
		else
			m_templatesArray[i] = NULL;
	}
}

/*
	Apply configuration loaded or modified to the app.
*/
void MainWindowImpl::applyConfiguration()
{
    setEditorColor(m_confManager->editorColor);
    setTreeColor(m_confManager->treeColor);

    if (m_confManager->useTrayIcon)
        m_trayIcon->show();
    else
        m_trayIcon->hide();

    if (mainModel != NULL)
        mainModel->setDateFormat(m_confManager->getFullDateFormat());
}

/*
	Display a warning when file is empty.
*/
void MainWindowImpl::setEmptyFileDisplay()
{
    textEdit->setHtml("<html><head></head><body style=\"background-color:transparent;\">&nbsp;<table align=\"center\" width=98% style=\"background-color:rgb(240, 240, 240);\"><tr><td><p style=\" font-family:'Sans Serif'; font-size:10pt;\" align=\"center\">" +
                      tr("This file is empty. Please add root categories and/or pages.") +
                      "</p></td></tr></table></body></html>");
}

/*
	Format modifications : implements changes in format.
*/

/*
	Apply format changes on text.
*/
void MainWindowImpl::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
{
    QTextCursor cursor = textEdit->textCursor();
    /* Code from the example. Don't find it useful.
    if (!cursor.hasSelection())
        cursor.select(QTextCursor::WordUnderCursor);    
    */
    cursor.mergeCharFormat(format);
    textEdit->mergeCurrentCharFormat(format);
}

/*
	Update actions state. Triggered by style change event from QTextEdit.
*/
void MainWindowImpl::onFontChanged(const QFont &f)
{
    comboFont->setCurrentIndex(comboFont->findText(QFontInfo(f).family()));
    comboSize->setCurrentIndex(comboSize->findText(QString::number(f.pointSize())));
    actionBold->setChecked(f.bold());
    actionItalic->setChecked(f.italic());
    actionUnderline->setChecked(f.underline());
}

/*
	Update color action drawing. Triggered by style change event from QTextEdit.
*/
void MainWindowImpl::onColorChanged(const QColor &c)
{
    QPixmap pix(16, 16);
    pix.fill(c);
    action_Color->setIcon(pix);
}

/*
	Update alignment actions. Triggered by alignment change event from QTextEdit.
*/
void MainWindowImpl::onAlignmentChanged(Qt::Alignment a)
{
    if (a & Qt::AlignLeft)
    {
        actionAlignLeft->setChecked(true);
    }
    else if (a & Qt::AlignHCenter)
    {
        actionAlignCenter->setChecked(true);
    }
    else if (a & Qt::AlignRight)
    {
        actionAlignRight->setChecked(true);
    }
    else if (a & Qt::AlignJustify)
    {
        actionAlignJustify->setChecked(true);
    }
}

/*
	Settings methods.
*/
void MainWindowImpl::writeSettings()
{
	/*
#ifdef Q_WS_WIN
    QSettings settings(Constantes::APP_NAME + ".ini", QSettings::IniFormat, 0);
#else
    QSettings settings(QSettings::IniFormat, QSettings::UserScope, Constantes::APP_NAME, Constantes::APP_NAME, 0);
#endif
	*/
	QSettings settings(QSettings::IniFormat, QSettings::UserScope, Constantes::APP_NAME, Constantes::APP_NAME, 0);

    settings.beginGroup("MainWindow");
    settings.setValue("geometry", this->saveGeometry());
    settings.endGroup();

    settings.beginGroup("Docks");
    settings.setValue("MainDocks", this->saveState());
    settings.endGroup();
}

void MainWindowImpl::readSettings()
{
	/*
#ifdef Q_WS_WIN
    QSettings settings(Constantes::APP_NAME + ".ini", QSettings::IniFormat, 0);
#else
    QSettings settings(QSettings::IniFormat, QSettings::UserScope, Constantes::APP_NAME, Constantes::APP_NAME, 0);
#endif
	*/

	QSettings settings(QSettings::IniFormat, QSettings::UserScope, Constantes::APP_NAME, Constantes::APP_NAME, 0);

    settings.beginGroup("MainWindow");
    this->restoreGeometry(settings.value("geometry").toByteArray());
    settings.endGroup();

    settings.beginGroup("Docks");
    this->restoreState(settings.value("MainDocks").toByteArray());
    settings.endGroup();
}

/*
	Events : slots programatically linked.
*/
void MainWindowImpl::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason)
    {
    case QSystemTrayIcon::DoubleClick:
        if (isMinimized())
        {
            setWindowState(windowState() & ~Qt::WindowMinimized | Qt::WindowActive);
        }
        else if (!isVisible())
        {
            show();
            activateWindow();
        }
        else
        {
            hide();
        }
    default:
        ;
    }
}

void MainWindowImpl::onActionSysShow()
{
    if (!this->isVisible())
        this->show();

    this->setWindowState(this->windowState() & ~Qt::WindowMinimized | Qt::WindowActive);
}

void MainWindowImpl::onActionSysClose()
{
    m_closeFromMenu = true;
    this->close();
}

void MainWindowImpl::onActionMenuMoveUp()
{
    QTreeWidgetItem *current = treeWidget->currentItem();
    QTreeWidgetItem *parent = current->parent();
    if (parent)
    {
        int index1 = parent->indexOfChild(treeWidget->currentItem());
        int index2;
        if (index1 > 0)
        {
            index2 = index1 - 1;

            QTreeWidgetItem *item1 = parent->child(index1);
            bool expanded1 = item1->isExpanded();

            item1 = parent->takeChild(index1);
            parent->insertChild(index2, item1);

            item1->setExpanded(expanded1);
            treeWidget->setCurrentItem(item1);

            mainModel->setFileModified(true);
        }
    }
    else
    {
        int index1 = treeWidget->indexOfTopLevelItem(treeWidget->currentItem());
        int index2;
        if (index1 > 0)
        {
            index2 = index1 - 1;

            QTreeWidgetItem *item1 = treeWidget->topLevelItem(index1);

            bool expanded1 = item1->isExpanded();

            item1 = treeWidget->takeTopLevelItem(index1);
            treeWidget->insertTopLevelItem(index2, item1);

            item1->setExpanded(expanded1);
            treeWidget->setCurrentItem(item1);

            mainModel->setFileModified(true);
        }
    }
}

void MainWindowImpl::onActionMenuMoveDown()
{
    QTreeWidgetItem *current = treeWidget->currentItem();
    QTreeWidgetItem *parent = current->parent();
    if (parent)
    {
        int index1 = parent->indexOfChild(treeWidget->currentItem());
        int index2;
        if (index1 < (parent->childCount() - 1))
        {
            index2 = index1 + 1;

            QTreeWidgetItem *item1 = parent->child(index1);

            bool expanded1 = item1->isExpanded();

            item1 = parent->takeChild(index1);

            parent->insertChild(index2, item1);

            item1->setExpanded(expanded1);
            treeWidget->setCurrentItem(item1);

            mainModel->setFileModified(true);
        }
    }
    else
    {
        int index1 = treeWidget->indexOfTopLevelItem(treeWidget->currentItem());
        int index2;
        if (index1 < (treeWidget->topLevelItemCount() - 1))
        {
            index2 = index1 + 1;

            QTreeWidgetItem *item1 = treeWidget->topLevelItem(index1);

            bool expanded1 = item1->isExpanded();

            item1 = treeWidget->takeTopLevelItem(index1);
            treeWidget->insertTopLevelItem(index2, item1);

            item1->setExpanded(expanded1);
            treeWidget->setCurrentItem(item1);

            mainModel->setFileModified(true);
        }
    }
}

void MainWindowImpl::onActionMenuMoveRight()
{
    QTreeWidgetItem *current = treeWidget->currentItem();
    QTreeWidgetItem *parent = current->parent();

    if (parent)
    {
        int index = parent->indexOfChild(treeWidget->currentItem());
        if (index > 0)
        {
            int parentIndex = index - 1;
            QTreeWidgetItem *newParent;

            newParent = parent->child(parentIndex);
            int dataIndex = newParent->data(0, Qt::UserRole).toUInt();
            QString type = mainModel->getType(dataIndex);

            if ((type == Constantes::TAG_CATEGORY) &&
                    (newParent != current))
            {
                QTreeWidgetItem *child = parent->takeChild(index);
                newParent->addChild(child);
                treeWidget->setCurrentItem(child);

                mainModel->setFileModified(true);
            }
        }
    }
    else
    {
        int index = treeWidget->indexOfTopLevelItem(treeWidget->currentItem());

        if (index > 0)
        {
            int parentIndex = index - 1;
            QTreeWidgetItem *newParent;

            newParent = treeWidget->topLevelItem(parentIndex);
            int dataIndex = newParent->data(0, Qt::UserRole).toUInt();
            QString type = mainModel->getType(dataIndex);

            if ((type == Constantes::TAG_CATEGORY) &&
                    (newParent != current))
            {
                QTreeWidgetItem *child = treeWidget->takeTopLevelItem(index);
                newParent->addChild(child);
                treeWidget->setCurrentItem(child);

                mainModel->setFileModified(true);
            }
        }
    }
}

void MainWindowImpl::onActionMenuMoveLeft()
{
    QTreeWidgetItem *current = treeWidget->currentItem();
    QTreeWidgetItem *parent = current->parent();
    int index;

    if (parent)
    {
        index = parent->indexOfChild(treeWidget->currentItem());
        QTreeWidgetItem *newParent = parent->parent();
        QTreeWidgetItem *moved = parent->takeChild(index);
        if (newParent)
            newParent->addChild(moved);
        else
            treeWidget->addTopLevelItem(moved);
        treeWidget->setCurrentItem(moved);

        mainModel->setFileModified(true);
    }
}

void MainWindowImpl::onActionAddRootCategory()
{
    QTreeWidgetItem *childItem;

    bool ok;
    QString newName = QInputDialog::getText(this, tr("New root category"),
                                            tr("New root category name :"), QLineEdit::Normal, tr("NewCategory"), &ok);

    if (ok)
    {
        int index = mainModel->addItem(newName, Constantes::TAG_CATEGORY, "", "", QDateTime::currentDateTime());

        childItem = new QTreeWidgetItem(treeWidget);

        // Setup icons and model.
        childItem->setIcon(0, mainModel->m_folderIcon);
        childItem->setText(0, newName);
        childItem->setData(0, Qt::UserRole, index);

        treeWidget->setCurrentItem(childItem);
        onTreeClick(childItem, 0);
    }
}

void MainWindowImpl::onActionAddRootPage()
{
    QTreeWidgetItem *childItem;

    bool ok;
    QString newName = QInputDialog::getText(this, tr("New root page"),
                                            tr("New root page name :"), QLineEdit::Normal, tr("NewPage"), &ok);

    if (ok)
    {
        int index = mainModel->addItem(newName, Constantes::TAG_PAGE, "", "", QDateTime::currentDateTime());

        childItem = new QTreeWidgetItem(treeWidget);

        // Setup icons and model.
        childItem->setIcon(0, mainModel->m_bookmarkIcon);
        childItem->setText(0, newName);
        childItem->setData(0, Qt::UserRole, index);

        treeWidget->setCurrentItem(childItem);
        onTreeClick(childItem, 0);
    }
}

void MainWindowImpl::onActionMenuAddCategory()
{
    QTreeWidgetItem *childItem;
    QTreeWidgetItem *item = treeWidget->currentItem();

    bool ok;
    QString newName = QInputDialog::getText(this, tr("New category"),
                                            tr("New category name :"), QLineEdit::Normal, tr("NewCategory"), &ok);

    if (ok)
    {
        int index = mainModel->addItem(newName, Constantes::TAG_CATEGORY, "", "", QDateTime::currentDateTime());

        if (item != NULL)
        {
            childItem = new QTreeWidgetItem(item);
            childItem->setFlags(item->flags());
        }
        else
            childItem = new QTreeWidgetItem(treeWidget);


        // Setup icons and model.
        childItem->setIcon(0, mainModel->m_folderIcon);
        childItem->setText(0, newName);
        childItem->setData(0, Qt::UserRole, index);

        treeWidget->setCurrentItem(childItem);
        onTreeClick(childItem, 0);
    }
}

void MainWindowImpl::onActionMenuAddPage()
{
    QTreeWidgetItem *childItem;
    QTreeWidgetItem *item = treeWidget->currentItem();

    bool ok;
    QString newName = QInputDialog::getText(this, tr("New page"),
                                            tr("New page name :"), QLineEdit::Normal, tr("NewPage"), &ok);

    if (ok)
    {
        int index = mainModel->addItem(newName, Constantes::TAG_PAGE, "", "", QDateTime::currentDateTime());

        if (item != NULL)
        {
            childItem = new QTreeWidgetItem(item);
            childItem->setFlags(item->flags());
        }
        else
            childItem = new QTreeWidgetItem(treeWidget);


        // Setup icons and model.
        childItem->setIcon(0, mainModel->m_bookmarkIcon);
        childItem->setText(0, newName);
        childItem->setData(0, Qt::UserRole, index);

        treeWidget->setCurrentItem(childItem);
        onTreeClick(childItem, 0);
    }
}

void MainWindowImpl::onActionMenuRename()
{
    QTreeWidgetItem *item = treeWidget->currentItem();
    if (item != NULL)
    {
        int index = item->data(0, Qt::UserRole).toUInt();
        QString name = mainModel->getName(index);

        bool ok;
        QString newName = QInputDialog::getText(this, tr("Rename"),
                                                tr("New name :"), QLineEdit::Normal,
                                                name, &ok);
        if (ok)
        {
            mainModel->changeName(index, newName);
            item->setText(0, newName);
        }
    }
}

void MainWindowImpl::onActionMenuDelete()
{
    QTreeWidgetItem *item = treeWidget->currentItem();
    if (item != NULL)
    {
        int index = item->data(0, Qt::UserRole).toUInt();
        QString name = mainModel->getName(index);

        QMessageBox::StandardButton ret = QMessageBox::question(this, tr("Delete"), tr("Do you want to delete this item ?"),
                                          QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);

        if (ret == QMessageBox::Ok)
        {
            // If the deleted item is in the editor, clear it.
            if (item == mainModel->getCurrentItem())
            {
                textEdit->clear();
                textEdit->setEnabled(false);
            }

            // Delete the item, but NOT its data in the model, as it will create an offset
            // with index which will mess up the whole thing ;)
            delete item;
            mainModel->setFileModified(true);
        }
    }
}

void MainWindowImpl::onActionMenuProperty()
{
    QTreeWidgetItem *item = treeWidget->currentItem();
    if (item != NULL)
    {
        int index = item->data(0, Qt::UserRole).toUInt();
        PropertyDlgImpl *propertyDlg = new PropertyDlgImpl(this, Qt::WindowTitleHint | Qt::WindowSystemMenuHint);

        propertyDlg->setupData(m_confManager->getFullDateFormat(),
                               mainModel->getName(index),
                               mainModel->getType(index),
                               mainModel->getTags(index),
                               mainModel->getCreationDate(index));

        int result = propertyDlg->exec();

		if (result == QDialog::Accepted)
		{
			mainModel->updateTags(index, propertyDlg->leTags->text());
			
			if (mainModel->getType(index) == Constantes::TAG_CATEGORY)
				onTreeClick(item, 0);
		}

        delete propertyDlg;
    }
}

/*
	When selecting a new item, update enabled state of "move" actions.
	A bit messy, but it works.
*/
void MainWindowImpl::onCurrentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
    if (mainModel != NULL)
    {
        QTreeWidgetItem *item = current;
        if (item != NULL)
        {
            actionMenuProperty->setEnabled(true);

            int index = item->data(0, Qt::UserRole).toUInt();
            QString type = mainModel->getType(index);

            if (type == Constantes::TAG_PAGE)
            {
                actionMenuAddPage->setEnabled(false);
                actionMenuAddCategory->setEnabled(false);
                actionMenuRename->setEnabled(true);
                actionMenuDelete->setEnabled(true);
            }
            else if (type == Constantes::TAG_CATEGORY)
            {
                actionMenuAddPage->setEnabled(true);
                actionMenuAddCategory->setEnabled(true);
                actionMenuRename->setEnabled(true);
                actionMenuDelete->setEnabled(true);
            }

            QTreeWidgetItem *parent = item->parent();
            QTreeWidgetItem *upParent;
            int index1;
            int index2;
            int count1;

            if (parent)
            {
                actionMenuMoveLeft->setEnabled(true);
                index1 = parent->indexOfChild(item);
                count1 = parent->childCount();
                if (index1 > 0)
                {
                    upParent = parent->child(index1 - 1);
                    index2 = parent->indexOfChild(upParent);

                    int dataIndex = upParent->data(0, Qt::UserRole).toUInt();
                    QString type = mainModel->getType(dataIndex);
                    if (type == Constantes::TAG_CATEGORY)
                        actionMenuMoveRight->setEnabled(true);
                    else
                        actionMenuMoveRight->setEnabled(false);
                }
                else
                    actionMenuMoveRight->setEnabled(false);
            }
            else
            {
                actionMenuMoveLeft->setEnabled(false);
                index1 = treeWidget->indexOfTopLevelItem(item);
                count1 = treeWidget->topLevelItemCount();
                if (index1 > 0)
                {
                    upParent = treeWidget->topLevelItem(index1 - 1);
                    index2 = treeWidget->indexOfTopLevelItem(upParent);

                    int dataIndex = upParent->data(0, Qt::UserRole).toUInt();
                    QString type = mainModel->getType(dataIndex);
                    if (type == Constantes::TAG_CATEGORY)
                        actionMenuMoveRight->setEnabled(true);
                    else
                        actionMenuMoveRight->setEnabled(false);
                }
                else
                    actionMenuMoveRight->setEnabled(false);
            }

            if (index1 == 0)
                actionMenuMoveUp->setEnabled(false);
            else
                actionMenuMoveUp->setEnabled(true);

            if (index1 == (count1 - 1))
                actionMenuMoveDown->setEnabled(false);
            else
                actionMenuMoveDown->setEnabled(true);
        }
        else
        {
            actionAddRootCategory->setEnabled(true);
            actionAddRootPage->setEnabled(true);

            actionMenuProperty->setEnabled(false);

            actionMenuAddPage->setEnabled(false);
            actionMenuAddCategory->setEnabled(false);
            actionMenuRename->setEnabled(false);
            actionMenuDelete->setEnabled(false);
            actionMenuMoveUp->setEnabled(false);
            actionMenuMoveDown->setEnabled(false);
            actionMenuMoveLeft->setEnabled(false);
            actionMenuMoveRight->setEnabled(false);
        }
    }
    else
    {
        actionAddRootCategory->setEnabled(false);
        actionAddRootPage->setEnabled(false);

        actionMenuProperty->setEnabled(false);

        actionMenuAddPage->setEnabled(false);
        actionMenuAddCategory->setEnabled(false);
        actionMenuRename->setEnabled(false);
        actionMenuDelete->setEnabled(false);
        actionMenuMoveUp->setEnabled(false);
        actionMenuMoveDown->setEnabled(false);
        actionMenuMoveLeft->setEnabled(false);
        actionMenuMoveRight->setEnabled(false);
    }
}

/*
	Display the popup menu on the treeview.
*/
void MainWindowImpl::onTreeContextMenuRequested(QPoint pos)
{
    if (mainModel != NULL)
    {
        onTreeClick(treeWidget->itemAt(pos), 0);
        contextMenu->exec(QCursor::pos());
    }
}

void MainWindowImpl::onSearchSelection(QTreeWidgetItem *treeItem, int selStart, int selLenght)
{
    treeWidget->setCurrentItem(treeItem);
    onTreeClick(treeItem, 0);

    if (selStart != -1)
    {
        QTextCursor cursor = textEdit->textCursor();
        cursor.setPosition(selStart, QTextCursor::MoveAnchor);
        cursor.setPosition(selStart + selLenght, QTextCursor::KeepAnchor);
        textEdit->setTextCursor(cursor);
    }
}

/*
	Click on TreeWidget : update the editor if necessary.
*/
void MainWindowImpl::onTreeClick(QTreeWidgetItem *treeItem, int col)
{
    if ((treeItem != NULL) &&
            (mainModel != NULL))
    {
        mainModel->updateDisplay(treeItem);
        setEditorColor(m_confManager->editorColor);

        // Font
        QString font = m_confManager->defaultFont;
        int fontIndex = comboFont->findText(font);
        if (fontIndex != -1)
        {
            comboFont->setCurrentIndex(fontIndex);
            onTextFamily(font);
        }
        // Font size
        QString fontSize = m_confManager->defaultFontSize;
        int fontSizeIndex = comboSize->findText(fontSize);
        if (fontSizeIndex != -1)
        {
            comboSize->setCurrentIndex(fontSizeIndex);
            onTextSize(fontSize);
        }
        // Font color
        QTextCharFormat fmt;
        fmt.setForeground(m_confManager->defaultFontColor);
        mergeFormatOnWordOrSelection(fmt);
        onColorChanged(m_confManager->defaultFontColor);
    }
}

/*
	Close the application.
*/
void MainWindowImpl::doClose()
{
    if (mainModel != NULL)
    {
        m_confManager->lastFile = mainModel->getFileName();
        m_confManager->searchWholeWord = searchBox->cbWholeWord->isChecked();
        m_confManager->searchCaseSensitive = searchBox->cbCaseSensitive->isChecked();
        m_confManager->searchInPages = searchBox->cbScopePage->isChecked();
        m_confManager->searchInCategories = searchBox->cbScopeCategory->isChecked();
        m_confManager->searchInTags = searchBox->cbScopeTags->isChecked();
    }
    else
        m_confManager->lastFile = "";

    m_trayIcon->hide();
    writeSettings();
    delete mainModel;
    delete m_confManager;	// Will save configuration.
    delete m_styleManager;	// Will save styles.
    delete m_templatesManager; // Will save templates;
}

/*
	Hide the application to tray.
*/
void MainWindowImpl::doCloseToTray()
{
    this->hide();
    if (m_confManager->showMessageOnCloseToTray)
        m_trayIcon->showMessage(Constantes::APP_DISPLAY_NAME,
                                Constantes::APP_DISPLAY_NAME + tr(" has been minimized to tray.\nYou can show it by double-clicking on its icon."),
                                QSystemTrayIcon::MessageIcon(QSystemTrayIcon::Information), 5000);
}

/*
	Close request.
*/
void MainWindowImpl::closeEvent(QCloseEvent *event)
{
    // m_closeFromMenu equals true when user has clicked on any of the quit menu,
    // but equals false when closing using top right window button.
    if ((m_closeFromMenu) ||
            (!m_confManager->useTrayIcon) ||
            ((m_confManager->useTrayIcon) &&
             (!m_confManager->closeToTray)))
    {
        m_closeFromMenu = false;
        if (mainModel != NULL)
        {
            if (mainModel->askForSaveAndSave(this))
            {
                event->accept();
                doClose();
            }
            else
                event->ignore();
        }
        else
        {
            event->accept();
            doClose();
        }
    }
    else
    {
        event->ignore();
        doCloseToTray();
    }
}

/*
Alignement actions triggered : change alignment.
*/
void MainWindowImpl::onTextAlign(QAction *a)
{
    if (a == actionAlignLeft)
        textEdit->setAlignment(Qt::AlignLeft);
    else if (a == actionAlignCenter)
        textEdit->setAlignment(Qt::AlignHCenter);
    else if (a == actionAlignRight)
        textEdit->setAlignment(Qt::AlignRight);
    else if (a == actionAlignJustify)
        textEdit->setAlignment(Qt::AlignJustify);
}

/*
Font combo change.
*/
void MainWindowImpl::onTextFamily(const QString &f)
{
    QTextCharFormat fmt;
    fmt.setFontFamily(f);
    mergeFormatOnWordOrSelection(fmt);
    textEdit->setFontFamily(f);
    textEdit->setFocus();
}

/*
Font size change.
*/
void MainWindowImpl::onTextSize(const QString &p)
{
    QTextCharFormat fmt;
    fmt.setFontPointSize(p.toFloat());
    mergeFormatOnWordOrSelection(fmt);
    textEdit->setFontPointSize(p.toFloat());
    textEdit->setFocus();
}

/*
Events : Automaticaly generated by QDevelop
*/
void MainWindowImpl::onClipboardDataChanged()
{
    actionPaste->setEnabled(!QApplication::clipboard()->text().isEmpty());
}

void MainWindowImpl::on_action_Quit_triggered()
{
    m_closeFromMenu = true;
    this->close();
}

void MainWindowImpl::openFile(QString fileName)
{
    // Delete old model.
    if (mainModel != NULL)
        delete mainModel;

    // Create new model and open the file.
    mainModel = new Model(treeWidget, textEdit, statusbar, fileName, m_confManager->getFullDateFormat());
    searchBox->setModel(mainModel);
    if (mainModel->open())
    {
        actionAddRootCategory->setEnabled(true);
        actionAddRootPage->setEnabled(true);

		if (!mainModel->isNagainaDocument())
		{
			QMessageBox::warning(this, tr("Warning"), tr("It seems that this document eitheir is not a Nagaina document, or is an old one (prior to version 0.2.0).\n\nIf you are sure it is a Nagaina document, simply save it. Otherwise, do not use this document."));
		}

        statusBar()->showMessage(tr("File opened : ") + mainModel->getFileName());
    }
    else
    {
        // Create an empty file.
        delete mainModel;
        mainModel = NULL;
        on_action_New_triggered();
        statusBar()->showMessage(tr("File not found."));
    }
}

/*
Open a file.
*/
void MainWindowImpl::on_action_Open_triggered()
{
    bool ret;

    // If a file is already opened, check if the user want to save it (and do it).
    if (mainModel != NULL)
        ret = mainModel->askForSaveAndSave(this);
    else
        ret = true;

    if (ret)
    {
        // Ask for filename.
        QString fileName = QFileDialog::getOpenFileName(this, tr("Open a file"),
                           QDir::currentPath(),
                           tr("XML Files (*.xml);;All files (*.*)"));
        if (fileName.isEmpty())
            return;

        openFile(fileName);
    }
}

/*
Create a new file.
*/
void MainWindowImpl::on_action_New_triggered()
{
    bool ret;

    // If a file is already opened, check if the user want to save it (and do it).
    if (mainModel != NULL)
        ret = mainModel->askForSaveAndSave(this);
    else
        ret = true;

    if (ret)
    {
        // Delete old model.
        if (mainModel != NULL)
            delete mainModel;

        // Create a new one.
        mainModel = new Model(treeWidget, textEdit, statusbar, "", m_confManager->getFullDateFormat());
        searchBox->setModel(mainModel);
        mainModel->setFileModified(false);

        actionAddRootCategory->setEnabled(true);
        actionAddRootPage->setEnabled(true);

        setEmptyFileDisplay();

        statusBar()->showMessage(tr("New file."));
    }
}

/*
Save current file.
*/
void MainWindowImpl::on_action_Save_triggered()
{
    if (mainModel != NULL)
    {
        if (mainModel->getFileName().isEmpty())
        {
            on_actionSave_as_triggered();
        }
        else
        {
            mainModel->save();
            statusBar()->showMessage(tr("File saved : ") + mainModel->getFileName());
        }
    }
}

/*
Save current file under a new name.
*/
void MainWindowImpl::on_actionSave_as_triggered()
{
    if (mainModel != NULL)
    {
        // Ask for name.
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save a file"),
                           QDir::currentPath(),
                           tr("XML Files (*.xml);;All files (*.*)"));
        if (fileName.isEmpty())
            return;

        mainModel->saveAs(fileName);

        statusBar()->showMessage(tr("File saved as : ") + mainModel->getFileName());
    }
}

/*
	Editor actions.
*/
void MainWindowImpl::on_actionBold_triggered()
{
    QTextCharFormat fmt;
    fmt.setFontWeight(actionBold->isChecked() ? QFont::Bold : QFont::Normal);
    mergeFormatOnWordOrSelection(fmt);
}

void MainWindowImpl::on_actionItalic_triggered()
{
    QTextCharFormat fmt;
    fmt.setFontItalic(actionItalic->isChecked());
    mergeFormatOnWordOrSelection(fmt);
}

void MainWindowImpl::on_actionUnderline_triggered()
{
    QTextCharFormat fmt;
    fmt.setFontUnderline(actionUnderline->isChecked());
    mergeFormatOnWordOrSelection(fmt);
}

void MainWindowImpl::on_textEdit_currentCharFormatChanged(QTextCharFormat format)
{
    onFontChanged(format.font());
    onColorChanged(format.foreground().color());
}

void MainWindowImpl::on_action_Color_triggered()
{
    QColor col = QColorDialog::getColor(textEdit->textColor(), this);
    if (!col.isValid())
        return;

    QTextCharFormat fmt;
    fmt.setForeground(col);
    mergeFormatOnWordOrSelection(fmt);
    onColorChanged(col);
}

void MainWindowImpl::on_textEdit_cursorPositionChanged()
{
    onAlignmentChanged(textEdit->alignment());
}

/*
	Misc. actions.
*/
void MainWindowImpl::on_actionAbout_Qt_triggered()
{
    QMessageBox::aboutQt(this, Constantes::APP_DISPLAY_NAME);
}

void MainWindowImpl::on_action_About_triggered()
{
    AboutDialogImpl *aboutDlg = new AboutDialogImpl(this, Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
    aboutDlg->setData(Constantes::APP_DISPLAY_NAME,
                      Constantes::APP_VERSION);
    aboutDlg->exec();
    delete aboutDlg;
}

void MainWindowImpl::on_actionPrint_triggered()
{
    if ((mainModel != NULL) &&
            (mainModel->getCurrentItem() != NULL))
    {
        QTextDocument *document = textEdit->document();
        QPrinter printer;

        QPrintDialog *dialog = new QPrintDialog(&printer, this);
        dialog->setWindowTitle(tr("Print Document"));
        if (dialog->exec() != QDialog::Accepted)
            return;

        document->print(&printer);
    }
}

void MainWindowImpl::on_actionExport_PDF_triggered()
{
    if ((mainModel != NULL) &&
            (mainModel->getCurrentItem() != NULL))
    {
        QString fileName = QFileDialog::getSaveFileName(this, tr("Export PDF"),
                           QString(), "*.pdf");
        if (!fileName.isEmpty())
        {
            if (QFileInfo(fileName).suffix().isEmpty())
                fileName.append(".pdf");

            QPrinter printer(QPrinter::HighResolution);
            printer.setOutputFormat(QPrinter::PdfFormat);
            printer.setOutputFileName(fileName);
            textEdit->document()->print(&printer);
        }
    }
}

void MainWindowImpl::on_actionPostScript_triggered()
{
    if ((mainModel != NULL) &&
            (mainModel->getCurrentItem() != NULL))
    {
        QString fileName = QFileDialog::getSaveFileName(this, tr("Export PostScript"),
                           QString(), "*.ps");
        if (!fileName.isEmpty())
        {
            if (QFileInfo(fileName).suffix().isEmpty())
                fileName.append(".ps");
            QPrinter printer(QPrinter::HighResolution);
            printer.setOutputFormat(QPrinter::PostScriptFormat);
            printer.setOutputFileName(fileName);
            textEdit->document()->print(&printer);
        }
    }
}

void MainWindowImpl::on_actionStyle_editor_triggered()
{
    StyleEditorImpl *styleEditor = new StyleEditorImpl(this, 0);
    styleEditor->setManagers(m_confManager, m_styleManager);
    styleEditor->exec();
    delete styleEditor;
	updateStylesActionList();
}

void MainWindowImpl::onComboSelectStyle(QString name)
{
	QAction *currentAction;
	for (int i = 0; i < m_stylesGroup->actions().count(); i++)
	{
		currentAction = m_stylesGroup->actions().at(i);
		if (currentAction->text() == name)
		{
			currentAction->setChecked(true);
			break;
		}
	}
}

void MainWindowImpl::onSelectStyle(QAction *a)
{
	int index = comboStyle->findText(a->text());
	if (index != -1)
		comboStyle->setCurrentIndex(index);
	else
		comboStyle->setCurrentIndex(0);
}

void MainWindowImpl::on_action_Apply_current_style_triggered()
{
    if ((comboStyle->count() > 0) &&
            (textEdit->isEnabled()))
    {
        int index = comboStyle->itemData(comboStyle->currentIndex(), Qt::UserRole).toUInt();
        // Font
        QString font = m_styleManager->getStyleFont(index);
        int fontIndex = comboFont->findText(font);
        if (fontIndex != -1)
        {
            comboFont->setCurrentIndex(fontIndex);
            onTextFamily(font);
        }
        // Font size
        QString fontSize = m_styleManager->getStyleSize(index);
        int fontSizeIndex = comboSize->findText(fontSize);
        if (fontSizeIndex != -1)
        {
            comboSize->setCurrentIndex(fontSizeIndex);
            onTextSize(fontSize);
        }
        // Font color
        QTextCharFormat fmt;
        fmt.setForeground(m_styleManager->getStyleColor(index));
        mergeFormatOnWordOrSelection(fmt);
        onColorChanged(m_styleManager->getStyleColor(index));
        // Bold, Italic, Underline
        actionBold->setChecked(m_styleManager->getStyleBold(index));
        on_actionBold_triggered();
        actionItalic->setChecked(m_styleManager->getStyleItalic(index));
        on_actionItalic_triggered();
        actionUnderline->setChecked(m_styleManager->getStyleUnderline(index));
        on_actionUnderline_triggered();
        // Alignment
        switch (m_styleManager->getStyleAlignment(index))
        {
        case 0 :
            actionAlignLeft->setChecked(true);
            onTextAlign(actionAlignLeft);
            break;
        case 1 :
            actionAlignCenter->setChecked(true);
            onTextAlign(actionAlignCenter);
            break;
        case 2 :
            actionAlignRight->setChecked(true);
            onTextAlign(actionAlignRight);
            break;
        case 3 :
            actionAlignJustify->setChecked(true);
            onTextAlign(actionAlignJustify);
            break;
        default :
            actionAlignLeft->setChecked(true);
            onTextAlign(actionAlignLeft);
            break;
        }
    }
}

void MainWindowImpl::on_action_Options_triggered()
{
    ConfigurationDlgImpl *confEditor = new ConfigurationDlgImpl(this, 0);
    confEditor->setConfigurationManager(m_confManager);
    int result = confEditor->exec();

    if (result == QDialog::Accepted)
        applyConfiguration();

    delete confEditor;
}

void MainWindowImpl::on_action_Search_triggered()
{
    bool initialVisibility = searchDock->isVisible();

    /* Check the action if necessary. */
    if (!searchDock->toggleViewAction()->isChecked())
        searchDock->toggleViewAction()->trigger();

    /* Ugly Hack : if the dock is floating and visible, focus will stick to the main window. 	*/
    /* In this case, we set the dock invisible/visible to give it focus.						*/
    /* Does not work under Linux...																*/
    if ((searchDock->isFloating()) &&
            (initialVisibility))
    {
        searchDock->setVisible(false);
        searchDock->setVisible(true);
    }

    searchBox->tabPanel->setCurrentIndex(0);
    searchBox->leSearchField->setFocus();
}

void MainWindowImpl::on_actionHelp_triggered()
{
    helpDlg->show();
}

void MainWindowImpl::on_actionInsert_current_date_triggered()
{
    if (textEdit->isEnabled())
    {
        textEdit->textCursor().insertText(QDate::currentDate().toString(m_confManager->dateFormat) + " ");
    }
}

void MainWindowImpl::on_actionInsert_current_time_triggered()
{
    if (textEdit->isEnabled())
    {
        textEdit->textCursor().insertText(QTime::currentTime().toString(m_confManager->timeFormat) + " ");
    }
}

void MainWindowImpl::on_actionInsert_image_triggered()
{
	if (textEdit->isEnabled())
	{
		InsertImageDlgImpl *insertImageDlg = new InsertImageDlgImpl(this, 0);
		insertImageDlg->cbCopyImage->setChecked(m_confManager->copyImageToUserDir);
		
		int result = insertImageDlg->exec();
		
		if (result ==QDialog::Accepted)
		{
			m_confManager->copyImageToUserDir = insertImageDlg->cbCopyImage->isChecked();
			QString fileName = insertImageDlg->leImageFile->text();
			bool copyImage = insertImageDlg->cbCopyImage->isChecked();
			
			if (!fileName.isEmpty())
			{
				QFileInfo sourceFile(fileName);
				if (sourceFile.exists())
				{
					if (copyImage)
					{
						QDir directory(Constantes::getConfigPath());
						if (!directory.exists(Constantes::IMAGES_DIRECTORY))
							directory.mkdir(Constantes::IMAGES_DIRECTORY);
						QString modelName = QFileInfo(mainModel->getFileName()).fileName();
						modelName.truncate(modelName.length() - 4);
						QString newFileName = QDir::toNativeSeparators(Constantes::getConfigPath() + 
																		Constantes::IMAGES_DIRECTORY + "/" +
																		modelName + "-" + sourceFile.fileName());
						QFileInfo newFile(newFileName);
						if (newFile.exists())
							QFile::remove(newFileName);
						QFile::copy(fileName, newFileName);
						textEdit->textCursor().insertHtml("<img src=\"" + newFileName + "\" />");
					}
					else
						textEdit->textCursor().insertHtml("<img src=\"" + fileName + "\" />");
				}
				else
					QMessageBox::information(this, tr("Warning"), tr("File does not exists."), QMessageBox::Ok);
			}
		}
		
		delete insertImageDlg;
	}
}

void MainWindowImpl::on_actionInsert_table_triggered()
{
    if (textEdit->isEnabled())
    {
        InsertTableDlgImpl *insertTable = new InsertTableDlgImpl(this, 0);

        int result = insertTable->exec();

        if (result == QDialog::Accepted)
        {            
        	Qt::AlignmentFlag alignmentHFlag = Qt::AlignLeft;
        	
        	int nbRows = insertTable->sbRowsNumber->value();
        	int nbColumns = insertTable->sbColumnNumber->value();        	
        	
			double cellSpacing = insertTable->dsbCellSpacing->value();
			double cellPadding = insertTable->dsbCellPadding->value();
			
			if (insertTable->rbHLeft->isChecked())
				alignmentHFlag = Qt::AlignLeft;
			else if (insertTable->rbHCenter->isChecked())
				alignmentHFlag = Qt::AlignHCenter;
			else if (insertTable->rbHRight->isChecked())
				alignmentHFlag = Qt::AlignRight;					
			        	
            QTextTableFormat *format = new QTextTableFormat();
            format->setCellSpacing(cellSpacing);
            format->setCellPadding(cellPadding);
            format->setAlignment(alignmentHFlag);
            
            textEdit->textCursor().insertTable(nbRows, nbColumns, *format);                                    
            
        }

        delete insertTable;
    }
}

void MainWindowImpl::on_actionModify_table_triggered()
{
	if ((textEdit->isEnabled()) &&
		(textEdit->textCursor().currentTable() != NULL))
    {    	    	
    	int nbRowsInit = textEdit->textCursor().currentTable()->rows();
    	int nbColsInit = textEdit->textCursor().currentTable()->columns();
    	
        InsertTableDlgImpl *insertTable = new InsertTableDlgImpl(this, 0);
        insertTable->setResizeMode(nbRowsInit, nbColsInit);

        int result = insertTable->exec();

        if (result == QDialog::Accepted)
        {               
        	int nbRows = insertTable->sbRowsNumber->value();
        	int nbColumns = insertTable->sbColumnNumber->value();        	        				                       
            
            if (nbRowsInit != nbRows)
            {
            	if (nbRows < nbRowsInit)
            	{
            		int delta = nbRowsInit - nbRows;
            		textEdit->textCursor().currentTable()->removeRows(nbRowsInit - delta, delta);
           		}
           		else
           		{
           			int delta = nbRows - nbRowsInit;
           			textEdit->textCursor().currentTable()->insertRows(nbRowsInit, delta);
          		}
           	}
           	
           	if (nbColsInit != nbColumns)
            {
            	if (nbColumns < nbColsInit)
            	{
            		int delta = nbColsInit - nbColumns;
            		textEdit->textCursor().currentTable()->removeColumns(nbColsInit - delta, delta);
           		}
           		else
           		{
           			int delta = nbColumns - nbColsInit;
           			textEdit->textCursor().currentTable()->insertColumns(nbColsInit, delta);
          		}
           	}
        }
        
        delete insertTable;
	}
}

void MainWindowImpl::onInsertTemplate()
{
	if (textEdit->isEnabled())
	{
		QAction *action = qobject_cast<QAction *>(sender());
		if (action)
		{
			QString data = m_templatesManager->getTemplateDataByName(action->text());
			if (!data.isNull())
			{
				textEdit->textCursor().insertHtml(data);
			}
		}
	}
}

void MainWindowImpl::on_actionTemplates_manager_triggered()
{
	TemplatesManagerDlgImpl *templateManager = new TemplatesManagerDlgImpl(this, 0);
	templateManager->setManager(m_templatesManager);
	
	if (textEdit->isEnabled())
		templateManager->setCurrentCursor(&textEdit->textCursor());
	
	templateManager->exec();
	updateTemplateActionList();
	delete templateManager;
}

void MainWindowImpl::on_actionSave_as_template_triggered()
{
	if (textEdit->isEnabled())
	{
		bool ok;
		QString newName = QInputDialog::getText(this, tr("New template"),
                                            tr("Template name:"), QLineEdit::Normal, tr("TemplateName"), &ok);

		if (ok)
		{
			if (!m_templatesManager->doTemplateExist(newName))
			{
				QString data = textEdit->toHtml();
				
				int startIndex = data.indexOf("<p");
				data = data.remove(0, startIndex);
				int endIndex = data.lastIndexOf("</p>");
				data = data.remove(endIndex + QString("</p>").length(), data.length() - endIndex);
				
				m_templatesManager->addTemplate(newName, data);
				updateTemplateActionList();
			}
			else
				QMessageBox::information(this, tr("Warning"), tr("Template already exists."), QMessageBox::Ok);
		}
	}
}
